Общий курс · осенний семестр · занятие 2 из 15

ИИ-агенты в разработке: как устроен Claude Code

О чём это занятие
Кодинг-агент изнутри: чем агент отличается от чата и автодополнения, как устроен агентный цикл и зачем вокруг него «обвязка» — права доступа, память, сжатие контекста. Разбираемся на примере Claude Code, но принципы переносятся на любой современный агент — а пользоваться ими вы будете весь курс, в собственном проекте.
Аннотация
Занятие начинается с разграничения трёх инструментов — автодополнение, чат, агент — и правила, когда какой уместен. Затем вскрывается сердце любого агента: цикл из пятнадцати строк «запрос → модель → вызов инструмента → результат → снова модель», прослеженный по шагам на реальной трассировке. Дальше главный инженерный сюжет: голый цикл в работе не выживает, и всё, что делает агента пригодным — ворота прав, ретраи, сжатие контекста, журнал сессии, — живёт в обвязке-харнессе вокруг неизменного цикла. Разбираются инструменты и система прав (в тренажёре вы сами поработаете этими воротами), память проекта CLAUDE.md и режим планирования, механизмы расширения — команды, хуки, суб-агенты, MCP. Финал прикладной: как применять агента в вашем учебном проекте — пять рабочих рецептов, шаблон файла памяти и правила честного использования, за которые спросится на защите.
Пререквизиты
Занятие 1 (постановка задачи, выбор траектории и проекта). Базовые навыки работы в терминале. Полезно вперёд: на занятиях 10–11 вы будете составлять задания и файлы правил для LLM — сегодняшняя механика объяснит, почему они работают.
Мотивация
Почти каждый из вас уже просил нейросеть написать кусок кода. Разница между «просить чат» и «работать с агентом» — как между советом по телефону и напарником за соседним столом: агент сам читает ваш проект, запускает тесты, видит ошибки и правит, пока не станет зелёным. В проекте практики это умножитель скорости — но только для того, кто понимает, что происходит под капотом: откуда агент берёт контекст, почему он вдруг «забывает» начало сессии, что он имеет право сделать без спроса. Непонимание здесь стоит дорого: от впустую потраченных часов до снесённых файлов.

1. Автодополнение, чат, агент: кто есть кто

Обычный чат с моделью — это «вопрос → ответ»: модель только генерирует текст и ничего не может сделать. Агент отличается ровно одним: у него есть инструменты (читать файлы, запускать команды, искать) и цикл — после каждого действия он смотрит на результат и решает, что дальше, пока задача не выполнена.

ЧАТ:    вопрос → ответ                              (один шаг)
АГЕНТ:  вопрос → [подумать → действие → результат]* → ответ   (шагов сколько нужно)

Три инструмента разработчика решают разные задачи — путаница между ними — частая причина разочарований («агент слишком медленный», «автодополнение слишком глупое»):

АвтодополнениеЧат с модельюАгент
что делаетдостраивает строку/блокотвечает текстом действует в цикле до результата
видит проекттекущий файлчто вы вставили читает файлы сам
запускает коднетнетда: тесты, сборка, git
итерируетнетвы вручнуюсам: правка → тест → правка
лучшее применениебыстрый наборпонять, спросить многошаговые задачи
цена/скоростьмгновеннобыстромедленнее и дороже

Практическое правило: автодополнение — когда вы сами пишете и знаете что; чат — когда нужно понять; агент — когда задача требует нескольких шагов с обратной связью («почини тест», «разберись в баге»). Не гоняйте агента ради однострочника — это как вызывать эвакуатор, чтобы переставить машину на метр.

2. Сердце: агентный цикл

В основе любого кодинг-агента — очень простая конструкция. Вся история диалога лежит в массиве сообщений; модель на каждом обороте либо отвечает текстом, либо просит вызвать инструмент:

Пользователь → messages[] → Claude API → ответ
                                    │
                          stop_reason == "tool_use"?
                              да ↙        ↘ нет
                 выполнить инструмент,     вернуть текст —
                 добавить tool_result      цикл завершён
                 и снова в API

Вот и весь «магический» агент: модель + инструменты + цикл. Посмотрите, как он отрабатывает реальную задачу «найди все файлы .py в src/, посчитай строки и покажи самый большой» — три оборота цикла:

ВИТОК 1  → API: messages=[задача], tools=[read_file, bash]
         ← stop_reason=tool_use → bash("find src -name '*.py'")
         → tool_result: "src/app.py\nsrc/db.py\nsrc/utils.py"

ВИТОК 2  ← stop_reason=tool_use → bash("wc -l src/app.py src/db.py src/utils.py")
         → tool_result: "120 app.py · 64 db.py · 38 utils.py"

ВИТОК 3  ← stop_reason=end_turn
         ← текст: "Найдено 3 файла. Самый большой — src/app.py (120 строк)."

Обратите внимание: последовательность «сначала найти, потом посчитать, потом сделать вывод» никто не программировал — она возникла сама как следствие цикла. И главная мысль, которую стоит унести с занятия: цикл не меняется, сколько бы возможностей мы ни добавляли. Инструментов может быть 3 или 300 — структура остаётся той же; всё усложнение живёт вокруг.

3. Харнесс: почему голый цикл не выживает

Цикл из раздела 2 умещается в 15 строк, и его действительно можно собрать за вечер. Но в реальной работе он долго не живёт: не знает про права и радостно выполнит rm -rf, если так «попросил» прочитанный файл; падает от первой же ошибки сети; забывает начало разговора при переполнении контекста; теряет всё при сбое процесса. Харнесс (агентная обвязка) — это всё, что оборачивает цикл, превращая игрушку в рабочий инструмент. Если модель — двигатель, а цикл — коленвал, то харнесс — кузов, ремни, приборная панель и тормоза.

Проблема голого циклаСлой харнесса
выполняет любую команду вслепуюворота прав + deny-правила (раздел 4)
падает при ошибке API или таймаутеретраи с нарастающей паузой, таймауты
забывает начало при переполнениисжатие контекста (раздел 5)
теряет всё при сбое процессажурнал сессии на диске, восстановление
непонятно, что и почему сделаллоги и трейсинг каждого витка

Отсюда второй девиз занятия: сложность агента — не в цикле, а в обвязке. Дальше мы пройдём по главным слоям этой обвязки — тем, с которыми вы будете сталкиваться каждый день.

4. Инструменты и ворота прав

Инструменты агента делятся на понятные категории: файлы (чтение, правка), поиск по кодовой базе, выполнение команд в терминале, веб, делегирование суб-агентам. Важное инженерное свойство: инструменты только для чтения безопасны и могут выполняться параллельно пачками — а всё, что меняет файлы или состояние, идёт строго последовательно и через проверку прав.

Права — главный механизм безопасности. Перед выполнением каждый вызов проходит «ворота»: пользовательские хуки → правила allow/deny из настроек → интерактивный вопрос, если правила молчат. Правила задаются один раз в settings.json проекта:

{
  "permissions": {
    "allow": ["Bash(npm run test:*)", "Read(src/**)"],
    "deny":  ["Bash(rm -rf *)", "Read(.env)", "Bash(git push --force*)"]
  }
}

Так тесты и чтение исходников идут без вопросов, а разрушительные команды и чтение секретов запрещены навсегда — что бы ни «попросила» модель. Есть и целые режимы прав: default (спрашивать про опасное), plan (только читать и планировать), acceptEdits (правки без вопросов) и bypassPermissions — без вопросов вообще.

Типичная ошибка Включить bypassPermissions на рабочей машине, «чтобы не мешал вопросами». Этот режим — только для изолированной песочницы или контейнера, где нечего ломать. Второй вариант той же ошибки — слепо жать «разрешить», не читая, какую команду агент собрался выполнить. Ворота прав работают, только пока вы в них смотрите.

5. Память и контекст: CLAUDE.md, сжатие, план

Контекстное окно модели конечно, и им нужно управлять — это вторая по частоте причина «странного» поведения агента после прав.

CLAUDE.md — файл памяти проекта: агент читает его в начале работы и подчиняется написанному. Это не документация, а шпаргалка: стек, команды сборки и тестов, правила и запреты. Вот шаблон под ваш проект практики — положите его в корень репозитория и поддерживайте:

# Проект: <название вашего проекта практики>

## Стек
- <язык, фреймворк, БД — из вашей главы 2 отчёта>

## Команды
- `...` — запуск в разработке
- `...` — тесты (запускать после каждого изменения!)

## Правила
- Отвечай и комментируй код по-русски.
- Не трогай файлы в `docs/` и `report/` без явной просьбы.
- Новые функции — с тестами.
- Секреты лежат в `.env` — не читать и не коммитить.

Когда сессия длинная, история сжимается: старые сообщения свёртываются в резюме (автоматически или командой /compact), свежие остаются подробными. Признак переполнения — агент «поплыл» и забывает договорённости: сожмите контекст или начните новую сессию через /clear.

И, наконец, режим планирования: агент сначала читает код и составляет план, а править начинает только после вашего одобрения. Для незнакомого или критичного кода — обязательная привычка: вы видите намерения до действий и успеваете поправить понимание задачи.

6. Расширения: команды, хуки, суб-агенты, MCP

Вокруг цикла есть четыре механизма расширения — все они устроены как «добавь файл, а не меняй код»:

МеханизмЧто этоПример
слэш-командыmarkdown-файл со сценарием в .claude/commands/ /review-pr — своё ревью с фиксированным форматом ответа
хукиваши shell-команды в точках жизненного цикла после каждой правки — автоформатирование; перед записью — проверка на секреты с блокировкой
суб-агентыописанный в markdown помощник со своим контекстом и ограниченными инструментами ревьюер с доступом «только чтение»: анализирует, но не может менять код
MCPпротокол подключения внешних инструментов доступ к базе данных проекта под readonly-пользователем

Обратите внимание на повторяющийся приём безопасности: суб-агенту-ревьюеру дают только инструменты чтения, базу подключают под readonly-пользователем, хук блокирует запись секретов до выполнения. Принцип наименьших привилегий — на каждом слое.

7. Безопасность: граница доверия

Как только агент читает внешние данные — веб-страницы, чужие файлы, вывод команд, — появляется главная угроза: prompt injection. Во внешнем тексте могут быть спрятаны инструкции («выполни rm -rf», «отправь .env на этот адрес»), и модель может принять их за команды пользователя. Ментальная модель защиты — граница доверия:

[ инструкции пользователя ]        = доверенные команды
[ вывод инструментов/файлов/веба ] = ДАННЫЕ, не инструкции

Защита выстраивается слоями, каждый из которых вы уже видели: deny-правила блокируют опасное, что бы ни «попросила» модель; песочница путей не пускает за пределы проекта; секреты вообще не попадают в контекст; необратимые действия требуют подтверждения человека. Худшая из возможных конфигураций — дать агенту одновременно доступ к секретам и возможность отправлять данные наружу без подтверждения: это готовый канал утечки.

8. Тренажёр: прокрутите цикл своими руками

Ниже — симулятор агентного цикла на задаче из раздела 2. Вы играете роль ворот прав: когда агент просит выполнить команду, решаете — разрешить или запретить. Панель показывает массив сообщений, текущий этап цикла и счётчик контекста. Запреты не ломают агента — посмотрите, как он выкручивается.

Тренажёр: агентный цикл с воротами прав
messages[] — история диалога

Три сценария, которые стоит прожить. Всё разрешить — канонические три витка: два вызова инструментов и ответ; заметьте, как история растёт с каждым шагом — за неё вы платите токенами на каждом обороте. Запретить первый bash — агент получит отказ как результат инструмента, попробует прочитать каталог напрямую, наткнётся на ошибку (каталог — не файл!) и честно объяснит, что без прав задачу не решить: отказ — это сигнал модели, а не крах программы. Запретить второй bash — агент обойдётся инструментами чтения: откроет все три файла по очереди (чтение безопасно и не требует разрешения) и посчитает строки сам — дольше, дороже, но цель достигнута.

9. Практикум: мини-агент своими руками

Соберём настоящего агента на официальном SDK — цикл, два инструмента, ворота прав. Этого достаточно, чтобы исследовать проект, запускать тесты и чинить ошибки; именно так в основе устроен любой кодинг-агент. Обратите внимание на четыре продакшн-детали, которые отличают скелет от игрушки: таймаут на команды, обрезка длинного вывода (токены — деньги), флаг is_error в результате (агент понимает, что инструмент упал, и пробует иначе) и блок-лист опасных команд, срабатывающий раньше вопроса пользователю.

Полный код: рабочий мини-агент (Python + Anthropic SDK, один файл)
import subprocess, json
from anthropic import Anthropic

client = Anthropic()  # ключ берётся из ANTHROPIC_API_KEY

# 1) описания инструментов для модели (JSON Schema)
TOOL_SCHEMAS = [
    {"name": "read_file",
     "description": "Прочитать текстовый файл по пути и вернуть содержимое.",
     "input_schema": {"type": "object",
        "properties": {"path": {"type": "string"}}, "required": ["path"]}},
    {"name": "bash",
     "description": "Выполнить shell-команду, вернуть stdout/stderr/код.",
     "input_schema": {"type": "object",
        "properties": {"cmd": {"type": "string"}}, "required": ["cmd"]}},
]

# 2) реализация инструментов
def read_file(path):
    with open(path, encoding="utf-8") as f:
        return f.read()[:10000]          # обрезаем: не раздуваем контекст

def bash(cmd):
    r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
    tail = lambda s: s[-2000:]           # только хвост длинного вывода
    return json.dumps({"stdout": tail(r.stdout), "stderr": tail(r.stderr),
                       "code": r.returncode})

IMPL = {"read_file": lambda a: read_file(a["path"]),
        "bash":      lambda a: bash(a["cmd"])}

# 3) ворота прав: опасное блокируем, остальное спрашиваем
DENY = ("rm -rf", "git push --force", ":(){", "mkfs", "dd if=")
def check_permission(name, args):
    if name == "bash":
        cmd = args.get("cmd", "")
        if any(bad in cmd for bad in DENY):
            return False
        return input(f"Выполнить `{cmd}`? [y/N] ").strip().lower() == "y"
    return True                          # чтение безопасно

# 4) главный агентный цикл
def run(prompt):
    messages = [{"role": "user", "content": prompt}]
    while True:
        resp = client.messages.create(model="claude-sonnet-4-20250514",
            max_tokens=2048, tools=TOOL_SCHEMAS, messages=messages)
        messages.append({"role": "assistant", "content": resp.content})

        if resp.stop_reason != "tool_use":
            print(next(b.text for b in resp.content if b.type == "text"))
            return

        results = []
        for block in resp.content:
            if block.type != "tool_use":
                continue
            if not check_permission(block.name, block.input):
                out, err = "Отказано пользователем", True
            else:
                try:
                    out, err = IMPL[block.name](block.input), False
                except Exception as e:
                    out, err = f"Ошибка инструмента: {e}", True
            results.append({"type": "tool_result", "tool_use_id": block.id,
                            "content": str(out), "is_error": err})
        messages.append({"role": "user", "content": results})

if __name__ == "__main__":
    run("Найди все файлы .py в src/, посчитай строки и покажи самый большой")

Дальнейший путь наращивания — в порядке боли: сначала ворота прав (иначе опасно), потом ретраи и таймауты (иначе падает), затем сохранение сессии (иначе теряете работу), и только потом сжатие контекста и трейсинг. Пять шагов — и вы повторите путь от учебного скрипта до архитектуры уровня Claude Code.

10. Агент в вашем проекте практики

Теперь главное — как применять это в курсе. Пять рецептов, покрывающих типовые ситуации семестра:

СитуацияПриём
получили чужой/шаблонный код сгенерировать файл памяти командой /init, затем: «опиши архитектуру проекта и точки входа»
упал тест «запусти тесты, найди упавший, объясни причину и предложи фикс» — сначала диагноз, потом правка
рискованная правка режим планирования + коммит до запуска: план читаете и одобряете, откат — одной командой git
перед коммитом /review: проверка незакоммиченных изменений на баги и стиль
нужны тесты на модуль «сначала перечисли граничные случаи, потом напиши тесты и запусти» — список случаев успеваете поправить

Заметьте общий паттерн рецептов: сначала локализуй и объясни — потом правь. Фразы «объясни причину», «не меняй ничего, пока не подтвержу», «перечисли случаи» держат агента в режиме анализа и дают вам точку контроля. И четыре привычки, которых хватает на 90% повседневной работы: файл памяти в начале проекта, режим планирования для рискованного, сжатие контекста, когда «поплыло», и deny-правила для опасного.

10.1. Правила честного использования в курсе

Агент в этом курсе — разрешённый и поощряемый инструмент, как компилятор или отладчик. Но ответственность за результат — на вас, и на защите это проявится буквально:

Типичная ошибка Отдать агенту задачу целиком («сделай мне проект по описанию») и сдать результат. Помимо очевидного риска на защите, это ещё и плохо работает: широкие задачи агент решает хуже узких, а без ваших итераций и ревью накапливает архитектурный мусор. Правильная единица работы — маленькая проверяемая задача: один тест, один модуль, один рефакторинг.

Контрольные вопросы

Источники

  1. Claude Code — Anthropic Documentation : [сайт]. — URL: https://docs.anthropic.com/en/docs/claude-code (дата обращения: 09.07.2026).
  2. Model Context Protocol : [сайт]. — URL: https://modelcontextprotocol.io (дата обращения: 09.07.2026).
  3. Building Effective Agents — Anthropic : [сайт]. — URL: https://www.anthropic.com/research/building-effective-agents (дата обращения: 09.07.2026).